<!doctype html>
<html lang="zh">
<head>
  <meta charset="UTF-8">
  <meta name="viewport"
        content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>磁强计</title>
  <link rel="stylesheet" href="/static/css/bootstrap.min.css">
  <link rel="stylesheet" href="/static/css/font-awesome.min.css">
  <link rel="stylesheet" href="/omsp/qv.css">
  <link rel="stylesheet" href="/omsp/qv-table.css">
  <script src="/static/js/jquery-3.6.0.min.js"></script>
  <script src="/static/js/echarts.5.5.js"></script>
  <script src="/static/js/echarts-gl.min.js"></script>
  <script src="/static/js/xtool.js?12"></script>
  <script src="/omsp/qv.js"></script>
  <style>
    th {
      width: 150px;
    }
    .btn-sm{
      padding: 4px 6px !important;
    }
    select, input{
      padding: 1px 2px !important;
    }
  </style>
</head>
<body class="real-panel">
<div class="d-flex flex-row bg-transparent" style="height: calc(100vh);">
  <div class="d-flex flex-grow-1 flex-column position-relative border">
    <div class="real pt-1" style="padding:4px 6px;border-bottom: 1px solid var(--box-color)">
      <button class="btn btn-primary btn-sm disactive-btn" onclick="main.realtime()" >实时</button>
      <button class="btn btn-primary btn-sm mx-1" id="history" onclick="main.history()">历史</button>
<!--      <button class="btn btn-primary btn-sm" onclick="$dld(main.cur_task,'.h5')">下载</button>-->
      <label id="r-task" class="ps-3"></label>
    </div>
    <div class="history d-flex flex-column">
      <div style="padding: 4px 6px;border-bottom: 1px solid var(--box-color);display: flex">
        <button class="btn btn-primary btn-sm " onclick="main.realtime()" id="realtime">实时</button>
        <button class="btn btn-primary btn-sm mx-1 disactive-btn" onclick="main.history()" >历史</button>
        <label class="ps-3">日期: <input type="date" id="day" onchange="main.changeDay()"></label>
        <label class="ps-1">任务: <select id="task" class="form-select-sm" style="min-width: 120px;max-width: 280px;"
                                        onchange="main.changeTask()"></select></label>
        <label>最大帧数：<span id="frm_max"></span></label>
        <label class="ps-1">帧号：
          <input type="number" id="frm_input" min="1" max="1" style="min-width: 100px;" >
          <input type="range" min="1" max='1' id="frm_range" onchange="main.changeFrmRange()" style="min-width: 200px"/>
        </label>
        <div class="flex-grow-1"></div>
         <button class="btn btn-primary btn-sm history" onclick="main.exportCSV(this)"><i class="fa fa-file-text"></i>下载帧信息</button>
      </div>
      <div class="py-2 d-flex align-items-center" style="padding: 0px 6px;">
<!--        <button class="btn btn-primary btn-sm" onclick="$dld(main.cur_task,'.h5')">下载</button>-->

        <label>时间范围(UTC+8):
          <input type="datetime-local" id="h-start">~ <input type="datetime-local" id="h-end">
        </label>
        <button class="btn btn-primary btn-sm ps-1" onclick="main.sample0(this)" style="width: 60px;">显示</button>
        <span style="width: 50px"></span>
        <label for="sample-method">抽样方法</label>
        <select id="sample-method" class="form-select-sm">
          <option value="g">组抽样</option>
          <option value="t">时间间隔(秒)</option>
        </select>
        <label for="sample-interval" class="ps-1">抽样间隔</label>
        <input type="number" min="0" id="sample-interval">
        <button class="btn btn-primary btn-sm" onclick="main.sample(this)">抽样</button>

<!--        <label class="ps-2">组间隔：<input type="number"  id="sample-grp" style="max-width: 120px" value="0"/></label>-->
<!--        <label class="ps-3">时间间隔(秒)：<input type="number"  id="sample-t" style="max-width: 120px" value="0"/></label>-->
<!--        <button class="btn btn-primary btn-sm" onclick="main.sampleTime(this)">时间抽样</button>-->

      </div>
      <!--<div class="pt-2">

      </div>-->
    </div>
    <div class="flex-grow-1 py-3 d-grid " style="grid-template-columns: auto auto;align-content: stretch;">
      <div class="position-relative">
        <div class="chart h-100 w-100 position-absolute"></div>
      </div>
      <div class="position-relative">
        <div class="chart h-100 w-100 position-absolute"></div>
      </div>
      <div class="position-relative">
        <div class="chart h-100 w-100 position-absolute"></div>
      </div>
      <div class="position-relative">
        <div class="chart h-100 w-100 position-absolute"></div>
      </div>
      <div class="position-relative">
        <div class="chart h-100 w-100 position-absolute"></div>
      </div>
      <div class="position-relative">
        <div class="chart h-100 w-100 position-absolute"></div>
      </div>
    </div>
  </div>
  <div class="d-flex flex-column border xinfo-panel1">
    <div class="bg-primary opacity-75 ps-1 py-1 text-white">科学数据信息</div>
    <div class="flex-grow-1 position-relative">
      <div class="position-absolute h-100 w-100 xbg-panel1">
        <table class="table table-bordered table-hover table-sm small">
          <tbody id="params">

          </tbody>
        </table>
      </div>
    </div>
  </div>
</div>
</body>
<script>
  var $INFO;
  var COLOR = ['red', 'green', 'blue']
  var ws
  var charts
  let ST = [
    {
      len: 1, offset: 0, d: {
        "0": "0b0：探头A关",
        "1": "0b1：探头A开"
      }
    },
    {
      len: 1, offset: 1, d: {
        "0": "0b0：探头B关",
        "1": "0b1：探头B开"
      }
    },
    {
      len: 1, offset: 2, d: {
        "0": "0b0：探头A地面模式",
        "1": "0b1：探头A科学模式（2048nT量程）"
      }
    },
    {
      len: 1, offset: 3, d: {
        "0": "0b0：探头B地面模式",
        "1": "0b1：探头B科学模式（2048nT量程）"
      }
    },
    {
      len: 2, offset: 4, d: {
        "00": "0b00：1Hz采样率",
        "01": "0b01：10Hz采样率",
        "10": "0b10：128Hz采样率"
      }
    },
    {
      len: 1, offset: 6, d: {
        "0": "0b0：主份FPGA上电",
        "1": "0b1：备份FPGA上电"
      }
    },
    {
      len: 1, offset: 7, d: {
        "0": "0b0：主份3.3V上电",
        "1": "0b1：备份3.3V上电"
      }
    },
    {
      len: 1, offset: 8, d: {
        "0": "0b0：模拟电路正常连接探头",
        "1": "0b1：模拟电路交叉连接探头"
      }
    },
    {
      len: 1, offset: 9, d: {
        "0": "0b0：数据未压缩",
        "1": "0b1：数据压缩"
      }
    },
    {len: 2, offset: 10, d: {}}
  ]
  let tofix3 = (v) => v.toFixed(3)
  let amag_params = [
        {n:"同步头", k: "syn", v: new RawFmt('4X').X, r: '4X'},
        {n:"帧计数", k: "cnt"  , r: '4X'  },
        {n:"时间码（探头AB第0组数据产生时间）", k: "ts",v:BJT},
        {n:"磁强计3.3V电压", k: "u"  ,v: tofix3,  r: '3X'  },
        {n:"磁强计工作状态", k: "zt"  , r: '3X',v: convertStatus },
        {n:"磁强计探头温度A", k: "T_A"  ,v: tofix3,  r: '3X'  },  // ${d.T_A}
        {n:"磁强计探头温度B", k: "T_B"  ,v: tofix3,  r: '3X'  },  // ${d.T_B}
        {n:"磁强计指令接收计数", k: "zl_cnt"  , r: '2X'  },  // ${d.zl_cnt}
        {n:"磁强计最后指令号", k: "zl"  , r: '2X'  },  // ${d.zl}
        {n:"磁强计伸杆脉冲计数", k: "mc_cnt"  , r: '2X'  },  // ${d.mc_cnt}
        {n:"磁强计探头相位", k: "ttxw"  , r: '4X'  },  // ${d.ttxw}
        {n:"磁强计信号处理单元模拟电路温度", k: "T_dl"  ,v: tofix3,  r: '3X'  },  // ${d.T_dl}
        {n:"磁强计定标线圈温度", k: "T_xq"  ,v: tofix3,  r: '3X'  },  // ${d.T_xq}
        {n:"串口通讯错误计数", k: "w_cnt"  , r: '1X'  },  // ${d.w_cnt}
        {n:"串口通讯错误类型", k: "w_type"  , r: '1X'  },  // ${d.w_type}
  ]

  class Page extends Realtime{
    constructor() {
      super('AMAG', getStation(), amag_params)
      // let dim = ['x', 'ax', 'ay', 'az', 'bx', 'by', 'bz']
      this.dim = ['x', 'y', null, null, null, null, null]
      this.body = document.querySelector('body')
      this.tasksUrl = day => `/-/omsp.tasks?ins=${this.key}/${this.station}&day=${day}`
      $INFO = $('#info');
      this.$startTime = $$('#h-start');
      this.$endTime = $$('#h-end');
      this.$sampleMethod = $$('#sample-method')
      this.$SampleInterval = $$('#sample-interval')
      this.cur_task = ''
      this.deffrm = 1
      this.fmin = this.deffrm
      this.fmax = this.deffrm
      let chartBox = Array.from(document.querySelectorAll('.chart'));
      charts = chartBox.map((v, i) => {
        let c = echarts.init(v)
        c.setOption(this.genOption(i))
        return c
      });
      this.$day.onchange = this.changeDay.bind(this)
      this.$task.onchange = this.changeTask.bind(this)
      this.$frmr.onchange = this.changeFrmRange.bind(this)
    }

    download() {
      if (this.cur_task === '') return
      let parms = parseTask(this.cur_task)
      let filename = `${parms.st}-${parms.orb}-${$INS}.h5`
      let url = `/-/omsp.downf?f=${this.cur_task}`
      downFile(url, filename)
    }

    async changeDay() {
      this.close()
      this.clearAll()
      await this.load_task();
    }

    async changeTask() {
      this.close();
      this.clearTask()

      await this.loadTask(this.$task.value)
      // await this.loadFrm()

    }

    async load_frames(task) {
      await super.load_frames(task);
      let s = BJT(this.frames[0].info.ts)
      let e = BJT(this.frames[this.frames.length -1].info.ts)
      this.$startTime.value = s.slice(0,19)
      this.$endTime.value = e.slice(0,19)
      await this.load_frame_chart(this.$frmr.value)
    }

    async load_frame_chart(index){

      let d = this.frames[parseInt(index)]
      let [offset, size] = d.frm;
      let bufr = await fetch(`/-/omsp.bindata?t=${main.cur_task}&offset=${offset}&size=${size}`).then(v => v.arrayBuffer())
      let data = new Float64Array(bufr)
      charts.forEach(c => {
        c.setOption({series: {data: data}})
      })
    }

    async changeFrmRange() {
      let frmid = parseInt(this.$frmr.value);
      this.clearFrmDisplay()
      // this.loadFrm()
      this.seek(frmid)
      await this.load_frame_chart(frmid)
    }

    genOption(i) {
      let A = 'XYZ'
      let B = 'AB'
      let title = `探头${B[i % 2]} ${A[parseInt(i / 2)]}轴磁场`;
      let dimIdx = (i % 2) * 3 + parseInt(i / 2) + 1
      return {
        title: {text: title, textStyle: {fontSize: 12}, left: 'center'},
        color: [COLOR[parseInt(i / 2)]],
        grid: {left: 100, top: 40, bottom: 30, right: 30},
        animation: false,
        dataZoom: [{type: 'inside', start: 0, end: 100}],
        tooltip: {trigger: 'axis'}, xAxis: {type: 'time'}, yAxis: {name: 'nT',axisLabel:{formatter: function (value){return Math.round(value).toString().replace(/\B(?=(\d{3})+(?!\d))/g,',');}}, axisLine: {show: true}, scale: true},
        // showSymbol: false,symbol: 'none'  scatterGL
        series: [{
          type: 'line', showSymbol: false,  dimensions: this.dim, encode: {
            x: 0,
            y: dimIdx
          }, lineStyle: {width: 1}, data: []
        }]
      }
    }


    realtime() {
      this.reset();
      this.body.classList = 'real-panel'
      $('#r-task').html('')
      this.clearFrmAll()
      super.realtime()
      this.resize();
    }

    async history() {
      this.close()
      this.reset()
      let selectedTask = this.cur_task
      this.body.classList = 'his-panel'
      if (ws) ws.close()
      this.clearAll()
      this.resize()
      if(selectedTask){
        let task = new Task(selectedTask)
        this.cur_task =  task.task
        this.$day.value = task.date()
      }

      /*await this.loadTasks()
      await this.loadTask(this.cur_task)
      await this.loadFrm()*/
      await this.load_task()
      // await this.load_frame_chart(this.$frmr.value)
    }

    async loadTasks() {
      let selected = this.cur_task
      let day = this.$day.value
      let tasks = await fetch(this.tasksUrl(day)).then(r => r.json())
       this.$task.innerHTML =tasks.map(v => {
          return `<option value='${v}'>${parseTask(v).label}</option>`
        }).join('');
        this.$task.value = selected
        this.cur_task = this.$task.value;
        if(!this.cur_task){
          this.$task.selectedIndex = 0
          this.cur_task = this.$task.value
        }
        if(this.cur_task){
          let task = new Task(this.cur_task)
          this.$day.value = task.date()
        }

    }

    clearAll() {
      this.cur_task = ''
      this.$task.innerHTML = ''
      this.clearTask()
    }

    clearTask() {
      this.cur_task = ''
      this.clearFrmAll()
    }

    clearFrmAll() {
      this.clearFrmInput()
      this.clearFrmDisplay()
    }

    clearFrmDisplay() {
      this.$info.innerHTML = ''
      this.clearChartData()
    }

    clearFrmInput() {
      let defv = 1
      this.frame_index = this.frame_max = 0
      this.$startTime.value = this.$endTime.value = ''
      // this.$SampleInterval.textContent = 0
      this.$SampleInterval.value = 0
    }

    async loadTask(task) {
      let selected = this.$task.value
      if (selected == '' || selected == null) return
      let resp = await fetch(`/-/omsp.amag.taskInfo?task=${task}/.h5`).then(r => r.json())
      if (resp.fmin != undefined) {
        this.frm = resp.fmin
        this.fmax = resp.fmax
        this.fmin = resp.fmin
        $('#frm-range').attr({min: this.fmin, max: this.fmax})
        $('#frm-num').attr({min: this.fmin, max: this.fmax})
        $('#frm-num').val(this.frm)
        $('#h-start').val(resp.tstart.slice(0, 19))
        $('#h-end').val(resp.tend.slice(0, 19))
        // $('#frm-cur').text(this.frm)
        $('#frm-max').text(this.fmax)

      }
    }

    async loadFrm() {
      if (this.cur_task == undefined || this.cur_task === '' || this.cur_task == null) return
      if (this.frm == undefined || this.frm === '' || this.frm == null) return

      let resp = fetch(`/-/omsp.amag.frmdata?task=${this.cur_task}/.h5&frm=${this.frm}`)

      // let frmInfo = await $api(`omsp.amag.frminfo?task=${this.cur_task}/.h5&frm=${this.frm}`)
      let rp = await resp
      if (rp.ok) {
        let buf = await rp.arrayBuffer()
        this.renderBuf(buf)
        this.params(this.frames_ori[this.frm])
        // set_frmInfo(frmInfo)
      }
    }

    renderBuf(buf) {
      // let arr = new Float64Array(buf, 0, buf.byteLength / Float64Array.BYTES_PER_ELEMENT);
      let arr = new Float64Array(buf);
      charts.forEach((c, i) => {
        c.setOption({series: {data: arr}})
      })
    }
    async sample0(btn) {
      btn.disable = true
      try{
        let start = $('#h-start').val()
        let end = $('#h-end').val()

        this.clearChartData()
        $('#sample-interval').val(0);
        charts.forEach(c=>c.showLoading())

        let buf = await $api(
          `omsp.amag.s?task=${this.cur_task}&inter=1&m=g&s=${start}&e=${end}`,
          null, (v) => v.arrayBuffer(), v => alert('ERROR')
        )
        this.renderBuf(buf)

      }finally {
        charts.forEach(c=>c.hideLoading())
        btn.disable = false
      }
    }
    async sample(btn) {
      btn.disable = true
      try{
        let start = $('#h-start').val()
        let end = $('#h-end').val()
        let ab_method = $('#sample-method').val()
        let inter = $('#sample-interval').val()
        this.clearChartData()
        charts.forEach(c=>c.showLoading())

        let buf = await $api(
          `omsp.amag.s?task=${this.cur_task}&inter=${inter}&m=${ab_method}&s=${start}&e=${end}`,
          null, (v) => v.arrayBuffer(), v => alert('ERROR')
        )
        this.renderBuf(buf)

      }finally {
        charts.forEach(c=>c.hideLoading())
        btn.disable = false
      }
    }
    async sampleTime(btn){
      btn.disable = true
      try{
        let timeInterval = parseFloat(this.$sampleTime.value)
        if(timeInterval <0) {
          window.alert('请填写有效抽样时间间隔!!!')
          return
        }
        this.clearChartData()
        charts.forEach(c=>c.showLoading())
         let buf = await $api(
          `omsp.amag.s?task=${this.cur_task}&inter=${timeInterval}&m=t&s=${this.$startTime.value}&e=${this.$endTime.value}`,
          null, (v) => v.arrayBuffer(), v => alert('ERROR')
        )
        this.renderBuf(buf)
      }finally {
        charts.forEach(c=>c.hideLoading())
        btn.disable = false
      }

    }

    async msg(e) {
      let d = JSON.parse(e.data)
      if (d.task) {
        let args = parseTask(d.task)
        this.cur_task = d.task
        $('#r-task').html('任务:' + args.label)
        this.clearFrmAll()
        return
      }
      this.newframe(d);
      let [offset, size] = d.frm;
      let bufr = await fetch(`/-/omsp.bindata?t=${main.cur_task}&offset=${offset}&size=${size}`).then(v => v.arrayBuffer())
      let data = new Float64Array(bufr)
      charts.forEach(c => {
        c.setOption({series: {data: data}})
      })
      this.params(d)
      // set_frmInfo(d.info)
    }

    clearChartData() {
      charts.forEach((v, i) => {
        v.clear();
        v.setOption(this.genOption(i))
      });
    }

    resize() {
      charts.forEach(v => v.resize());
    }

    reset(){
      super.reset()
      this.clearFrmAll()
    }
  }

  let main
  window.onload = () => {
    $INS = 'AMAG'
    main = new Page()
    main.realtime()
    window.onresize = main.resize
  }



  function convertStatus(v) {
    let sBin = Number(v).toString(2).padStart(12, 0)
    return ST.slice(0, -1).map(v => {
      return v.d[sBin.slice(v.offset, v.offset + v.len)]
    }).join('<br>')
  }



  function set_frmInfo(d) {
    $INFO.html(`
          <tr>
            <th>同步头</th>
            <td>${d.syn ? ("0x" + Number(d.syn).toString(16).padStart(4, 0)) : undefined}</td>
          </tr>
          <tr>
            <th>帧计数</th>
            <td>${d.cnt}</td>
          </tr>
          <tr>
            <th>时间码（探头AB第0组数据产生时间）</th>
            <td>${d.time}</td>
          </tr>
          <tr>
            <th>磁强计3.3V电压</th>
            <td>${d.u}</td>
          </tr>
          <tr>
            <th title="【探头A状态、探头B状态】">磁强计工作状态</th>
            <td style="font-size: 12px">${convertStatus(d.zt)}</td>
          </tr>
          <tr>
            <th>磁强计探头温度A</th>
            <td>${d.T_A}</td>
          </tr>
          <tr>
            <th>磁强计探头温度B</th>
            <td>${d.T_B}</td>
          </tr>
          <tr>
            <th>磁强计指令接收计数</th>
            <td>${d.zl_cnt}</td>
          </tr>
          <tr>
            <th>磁强计最后指令号</th>
            <td>${d.zl}</td>
          </tr>
          <tr>
            <th>磁强计伸杆脉冲计数</th>
            <td>${d.mc_cnt}</td>
          </tr>
          <tr>
            <th>磁强计探头相位</th>
            <td>${d.ttxw}</td>
          </tr>
          <tr>
            <th>磁强计信号处理单元模拟电路温度</th>
            <td>${d.T_dl}</td>
          </tr>
          <tr>
            <th>磁强计定标线圈温度</th>
            <td>${d.T_xq}</td>
          </tr>
          <tr>
            <th>串口通讯错误计数</th>
            <td>${d.w_cnt}</td>
          </tr>
          <tr>
            <th>串口通讯错误类型</th>
            <td>${d.w_type}</td>
          </tr>
    `)
  }

  function realtime() {
    main.realtime()
    console.log('AMAG.REALTIME', $STATION)
  }

  function history() {
    main.history()
    console.log('amag.history', $STATION)
  }

  var REG_TSK = /(?<s>\/.*)\/(?<st>.+?)\/(?<orb>(?<day>(?<y>20\d{2})(?<m>\d{2})(?<d>\d{2})).*?)\//

  function parseTask(v) {
    let grp = REG_TSK.exec(v).groups
    grp.label = grp.orb + '/' + grp.st
    return grp
  }
</script>
</html>